﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.Algorithm.Data;

namespace AAA.Algorithm.Cluster.SOM
{
    public class SOM : AbstractCluster
    {
        private int intN = 0;
        private int intM = 0;
        private int intR = 0;

        public SOM(int N, int M, int R, List<string> FactorList, float ValueMin, float ValueMax)
        {
            intN = N;
            intM = M;
            intR = R;
            IsRemoveEmptyNode = false;
             for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < M; j++)
                {
                    SOMMapNode mapNode = new SOMMapNode();
                    INeuron InitalWeights = new Neuron();
                    Random RValue = new Random();
                    foreach (string k in FactorList)
                    {
                        InitalWeights.SetFactor(k, (float)(RValue.NextDouble() * (ValueMax -ValueMin) + ValueMin));
                    }
                    mapNode.SetInitialWeight(InitalWeights);
                    SetMapNode(i.ToString() + "-" + j.ToString(), mapNode);
                }
            }
        }

        protected override void PostCluster(float fSimilarity, float fMaxSimilarity, object oMapNodeKey, INeuron neuron, Dictionary<object, AbstractMapNode> dicCluster)
        {
            try
            {
                for (int r = 0; r <= intR; r++)
                {
                    List<string> lstNeighboKey = new List<string>();
                    SOMMapNode CurNode = (SOMMapNode)dicCluster[(string)oMapNodeKey];
                    CurNode.UpdateWeight(neuron, r + 1, intR);
                    lstNeighboKey = GetNeighorhood((string)oMapNodeKey, r);
                    foreach (string strKey in lstNeighboKey) {
                        CurNode = (SOMMapNode)dicCluster[strKey];
                        CurNode.UpdateWeight(neuron, r + 1, intR + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + "," + ex.StackTrace);
            }
        }

        private List<String> GetNeighorhood(string strKey, int intDistance) {
            List<string> lstResult = new List<string>();
            string[] M_N = strKey.Split('-');
            for (int i = 0; i < intM; i++) {
                for (int j = 0; j < intN; j++)
                {
                    if ((Math.Abs(i - int.Parse(M_N[0])) == intDistance) && (Math.Abs(j - int.Parse(M_N[1])) <= intDistance))
                    {
                        lstResult.Add(i.ToString() + '-' + j.ToString());
                    }
                    else if ((Math.Abs(i - int.Parse(M_N[0])) <= intDistance) && (Math.Abs(j - int.Parse(M_N[1])) == intDistance)) {
                        lstResult.Add(i.ToString() + '-' + j.ToString());
                    }
                }
            }
            return lstResult;
        }

        public void PrintResult() {
            foreach(string i in GetClusterName()) {
                SOMMapNode sMapNode = (SOMMapNode)GetCluster(i);
                INeuron NodeWeight = sMapNode.GetWeights();
                Console.WriteLine(i + "Weight:");
                PrintNode(NodeWeight);
                Console.WriteLine("Sample:");
                for (int j = 0; j < GetCluster(i).SampleCount; j++)
                {
                    INeuron NodeSample = GetCluster(i).GetSample(j);
                    PrintNode(NodeSample);
                }
                Console.WriteLine(GetCluster(i).SampleCount.ToString());
            }
        }

        private void PrintNode(INeuron NodeNeuron) {
            string strOutput = "F-";
            foreach(string strFactorName in NodeNeuron.GetFactorNames) {
            //    Console.Write(strFactorName + ":" + NodeNeuron.GetFactor(i).ToString() + ";");
                strOutput = strOutput +  NodeNeuron.GetFactor(strFactorName).ToString() + ";";
            }
            strOutput = strOutput + "A-";
            foreach(string strAttributeName in NodeNeuron.GetAttributeNames) {
             //   Console.Write(i.ToString() + ":" + NodeNeuron.GetAttribute(i).ToString() + ";");
                strOutput = strOutput +  NodeNeuron.GetAttribute(strAttributeName).ToString() + ";";
            }
            Console.WriteLine(strOutput);
        }
    }
}
